﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using SpaceMan.Physics;
using SpaceMan.Entities;
using SpaceMan.Particles;

namespace SpaceMan
{
    public static class S_Global
    {
        static SoundEffect fallBackAudio;
        static C_Drawing fallBack;
        static Dictionary<string, Texture2D> textureDictionary;
        static Dictionary<string, DrawContents> drawDictionary;
        static Dictionary<string, SoundEffect> audioDictionary;
        static ContentManager Content;
        static GraphicsDevice GraphicsDevice1;
        static GameTime GameTime1;
        public static float TIMESCALE;
        public static Action<PHY_Base, string> AddBody;
        
        public static Vector2 screenPosition;
        public static float ZoomFactor;
        public static AudioListener GlobalListener;

        public static Action<string> TRYCOMMAND;
        public static Action<string, Vector2> addEntity;
        public static Action<I_Entity> giveEntity;
        public static Action<I_Particle> giveParticle;

        public static void OnGameStart(ContentManager content, GraphicsDevice graphicsDevice, Action<PHY_Base, string> addBody)
        {
            
            GlobalListener = new AudioListener();
            GlobalListener.Position = Vector3.Zero;
            Content = content;
            textureDictionary = new Dictionary<string, Texture2D>();
            drawDictionary = new Dictionary<string, DrawContents>();
            audioDictionary = new Dictionary<string, SoundEffect>();
            
            GraphicsDevice1 = graphicsDevice;
            fallBackAudio = getSound("beep");
            fallBack = getDraw("null");
            AddBody = addBody;

        }

        public static void secondINIT(Action<I_Entity> GiveEntity, Action<string, Vector2> AddEntity, Action<I_Particle> GiveParticle)
        {
            giveParticle = GiveParticle;
            giveEntity = GiveEntity;
            addEntity = AddEntity;
        }

        public static void EachFrame(GameTime gameTime, float timeScale)
        {
            GameTime1 = gameTime;
            TIMESCALE = timeScale;
        }

        public static Rectangle CurrrentlyVisibleWorld()
        {
            return new Rectangle((int)screenPosition.X, (int)screenPosition.Y, (int)(GraphicsDevice1.Viewport.Width / ZoomFactor), (int)(GraphicsDevice1.Viewport.Height / ZoomFactor));
        }

        public static float getTimescale()
        {
            return GameTime1.ElapsedGameTime.Milliseconds * TIMESCALE;
        }


        public static SoundEffect getSound(string fileName)
        {
            if (audioDictionary.ContainsKey(fileName))
            {
                return audioDictionary[fileName];
            }

            else
            {
                try
                {
                    SoundEffect SE = Content.Load<SoundEffect>("SFX//" + fileName);
                    audioDictionary.Add(fileName, SE);
                    return SE;
                }

                catch
                {
                    return fallBackAudio;
                }
            }
        }

        public static C_Drawing getDraw(string fileName)
        {
            if(drawDictionary.ContainsKey(fileName))
            {
                return new C_Drawing(drawDictionary[fileName].Texture, drawDictionary[fileName].GlowMask, drawDictionary[fileName].AnimationDictionary);
            }

            else
            {
                StreamReader streamReader = null;
                string fileContents = "";


                Texture2D tex = new Texture2D(GraphicsDevice1, 1, 1);

                try
                {
                    streamReader = new StreamReader(Environment.CurrentDirectory + "\\Configurations\\Textures\\" + fileName + ".cfg");
                }

                catch
                {
                    return fallBack;
                }


                fileContents = streamReader.ReadToEnd();

                string replaceWith = "";
                fileContents = fileContents.Replace("\r\n", replaceWith).Replace("\n", replaceWith).Replace("\r", replaceWith);

                Dictionary<string, AnimationStructure> animationDictionary = new Dictionary<string, AnimationStructure>();
                string[] splitFile = fileContents.Split(';');
                Texture2D glo;

                if (textureDictionary.ContainsKey(splitFile[0]))
                {
                    tex = textureDictionary[splitFile[0]];
                }

                else
                {
                    try
                    {
                        tex = Content.Load<Texture2D>(splitFile[0]);
                        textureDictionary.Add(splitFile[0], tex);
                    }

                    catch
                    {
                        return fallBack;
                    }
                }

                if (textureDictionary.ContainsKey(splitFile[0] + "_Glow"))
                {
                    glo = textureDictionary[splitFile[0] + "_Glow"];
                }

                else
                {
                    try
                    {
                        glo = Content.Load<Texture2D>(splitFile[0] + "_Glow");
                        textureDictionary.Add(splitFile[0] + "_Glow", glo);
                    }

                    catch
                    {
                        glo = null;
                    }
                }



                for (int i = 1; i < splitFile.Length; i++)
                {
                    if (splitFile[i] != "")
                    {
                        string[] tempArray = splitFile[i].Split(',');
                        bool isAnimated = false;
                        bool isLooped = false;

                        try
                        {
                            if (tempArray[5] == "T")
                            {
                                isAnimated = true;
                            }

                            if (tempArray[6] == "T")
                            {
                                isLooped = true;
                            }
                            AnimationStructure animation;
                            animation.animationName = tempArray[0];
                            animation.frameTime = (float)Convert.ToDecimal(tempArray[1]);
                            animation.startPosition = Convert.ToInt32(tempArray[2]);
                            animation.width = Convert.ToInt32(tempArray[3]);
                            animation.height = Convert.ToInt32(tempArray[4]);
                            animation.animated = isAnimated;
                            animation.loop = isLooped;
                            animation.length = Convert.ToInt32(tempArray[7]);
                            animation.origin = new Vector2((float)Convert.ToDecimal(tempArray[8]), (float)Convert.ToDecimal(tempArray[9]));

                            animationDictionary.Add(animation.animationName, animation);
                        }

                        catch
                        {
                            return fallBack;
                        }
                    }
                }

                if (animationDictionary.Count > 0)
                {
                    

                    if(!drawDictionary.ContainsKey(fileName))
                    {
                        DrawContents contents = new DrawContents();
                        contents.Texture = tex;
                        contents.GlowMask = glo;
                        contents.AnimationDictionary = animationDictionary;
                        drawDictionary.Add(fileName, contents);
                    }

                    C_Drawing draw = new C_Drawing(tex, glo, animationDictionary);
                    return draw;
                }

                else
                {
                    return fallBack;
                }
            }

        }

        public static T DeepCopy<T>(this T original) where T : class
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(memoryStream, original);
                memoryStream.Seek(0, SeekOrigin.Begin);
                return (T)binaryFormatter.Deserialize(memoryStream);
            }
        }

        public static Vector2 getRotPos(Vector2 point, Vector2 origin, float rotation)
        {
            return Vector2.Transform(point - origin, Matrix.CreateRotationZ(rotation)) + origin;
        }
    }
}
